package de.hmm.hwip.connection.input;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.json.JSONObject;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;

import android.util.Log;

import de.hmm.hwip.messagehandler.api.IMessageHandler;
import de.hmm.hwip.security.api.ISecurityServer;

/**
 * 
 * Network thread to react on incomming connection
 *  
 * @author johannes Mendel
 * @version 28.09.2012
 *
 */
public class InConThread implements Runnable {

	/**
	 * Class identifier TAG
	 */
	private final String TAG = "InConThread (conn. service)";
	
	/**
	 * socket of the incoming connection
	 */
	private Socket connection;
	
	/**
	 * OSGi context
	 */
	private BundleContext context;
	
    /**
     * service tracker to get the messagehandler service.
     */
	private ServiceTracker serviceTracker;
	
	/**
	 * service for security server site
	 */
	private ISecurityServer serviceServerSecurity;
	
	/**
	 * messagehandler service
	 */
	private IMessageHandler messageService;
	
	/**
	 * Server Security service tracker
	 */
	private ServiceTracker secuServiceTracker;
	
	/**
	 * sends responses to Gui
	 */
	//private IResponse response;
	
	/**
	 * incoming json Object
	 */
	private JSONObject jsonObject;
	
	/**
	 * Constructor to generate a new instance
	 * 
	 * @param connection - socket connection
	 * @param context - bundle context
	 */
	public InConThread(Socket connection, BundleContext context){
		this.connection = connection;
		this.context = context;
		
		// getting messagehandler service via service tracker and route it to messageService
		serviceTracker = new ServiceTracker(this.context, IMessageHandler.class.getName(), null );
		serviceTracker.open();
		
		//getting the security services
		secuServiceTracker = new ServiceTracker(this.context, ISecurityServer.class.getName(), null);
		secuServiceTracker.open();
	}
	
	@Override
	public void run() {
		// incoming stream from spot or gateway
		BufferedReader bis = null; 
		boolean securityFlag = false;
		
		//wait for security service if not received first time
		while(true){
			serviceServerSecurity = (ISecurityServer) secuServiceTracker.getService();
			if(serviceServerSecurity != null){
				break;
			}else{
				try {
					wait(2000);
				} catch (InterruptedException e) {
					Log.e(TAG, "wait for Server Security Service exception: " + e.getMessage());
				}
			}
		}
		
		//wait for messagehandler service if not received first time
		while(true){
			messageService = (IMessageHandler) serviceTracker.getService();
			if(messageService != null){
				break;
			}else{
				try {
					wait(2000);
				} catch (InterruptedException e) {
					Log.e(TAG, "wait for messagehandler service exception: " + e.getMessage());
				}
			}
		}
		
		try
		{
			// getting streams
			bis= new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
			
			// getting time of in coming connection
			SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd H:m:s");
			Date today = new Date();
			
			// print time and port of the incoming connection
			Log.i(TAG, dataFormat.format(today) + " - Connections accepted on port: " + connection.getPort());

			//reads message, ends with #.#
			for(String input; !(input = bis.readLine()).contains("#.#");)
			{
				Log.i(TAG, "Received:" + input);	
	    		
	    		// will not throw if there is a non-crypted request or a crypt-key request
	    		try{
	    			
	    		 	// try to get the jsonobject and service
			    	jsonObject = new JSONObject(input);
			    	jsonObject.get("service");
	    
	    		}catch(Exception e)
	    		{
	    			Log.w(TAG, "Exception at Json parsing, certenly because of encrypted string");
	    			// if we have a secure AES connection
	    			input = serviceServerSecurity.decryptStringAES(input);
	    			
	    			if(input.equals("bpe")){
	    				
	    				String service = "hwip.processing.Spot";
	    				if(messageService != null){
	    					messageService.startAction(service, this.context, 
	    						new JSONObject().put("command", "getaeskey").put("service", service), 
	    						this.connection, false);
	    				}
	    				
	    				Log.e(TAG, "Security Exception. reperforme handshake.\n" + e.getMessage());
	    			}
		    		
		    		//get the jsonObject and service
			    	jsonObject = new JSONObject(input);
			    	jsonObject.get("service");
			    	
			    	//security is required
			    	securityFlag = true; 
			   
	    		}
	    		
	    		if (messageService != null)
		    	{
		    		// when the message service exists, start that message
		    		// service Action. There will be new instance of the 
	    			// requested service generated via FQD
		    		messageService.startAction((String)jsonObject.get("service"),this.context, jsonObject, this.connection, securityFlag);
		    	}
		    	else
		    	{
		    		Log.w(TAG, "In-Connection Thread - Message Service not available");
		    	}
			}
			
			//close Reader
			bis.close();
			
			Log.i(TAG, "In-Connection Thread finished");
			
			/*
			// getting gui service via service tracker
			serviceTracker = new ServiceTracker(this.context, IResponse.class.getName(), null );
			serviceTracker.open();
	    	response = (IResponse) serviceTracker.getService();
	    	if(response!= null){
	    		response.responseText("done");
	    	}else
	    		System.out.println("No Gui to send response: " + response.toString());
	    		*/
			
		}catch(Exception e)
		{
			Log.e(TAG, "Something really bad gone wrong.\nOr received message wasn't parseable.\n" + e.getMessage());
		}
	}
	

}
